import java.awt.image.BufferedImage;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.jdom2.Content;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class Datamanager {

	public static String PATH;
	public static org.jdom2.Element currentRunGlobal;
	public static org.jdom2.Document DOCUMENT;
	public static File FILE;
	public static org.jdom2.Element ACTIVE_BUILD;
	public static List<org.jdom2.Element> BUILD_LIST;

	public Datamanager(String path) throws JDOMException, IOException {
		this.PATH = path;
		DOCUMENT = null;
		FILE = new File(PATH);
		SAXBuilder builder = new SAXBuilder();
		DOCUMENT = builder.build(FILE);
		BUILD_LIST = getBuildList();
		String lastActivBuildName = DOCUMENT.getRootElement().getChild("programmStatus").getChild("lastActivBuild").getValue();
		ACTIVE_BUILD = getActivBuild(lastActivBuildName);

	}

	public static void addStatus(int activBuild, Boolean startend, int id,
			String date, String GOLD, String XP, Long length)
			throws JDOMException, IOException {

//		org.jdom2.Element currentBuild = getActivBuild(DOCUMENT, FILE);
		org.jdom2.Element runList = ACTIVE_BUILD.getChild("runList");

		if ((date != null && GOLD != null && XP != null)
				&& (GOLD != "" && XP != "")) {

			if (startend) {
				// new RUN

				org.jdom2.Element run = new org.jdom2.Element("run");
				org.jdom2.Element runID = new org.jdom2.Element("id");
				runID.addContent(String.valueOf(id)); // TODO vortlaufende ID
														// adden
				org.jdom2.Element startDate = new org.jdom2.Element("startDate");
				org.jdom2.Element endDate = new org.jdom2.Element("endDate");
				org.jdom2.Element runLength = new org.jdom2.Element("runLength");
				org.jdom2.Element gainXP = new org.jdom2.Element("gainXP");
				org.jdom2.Element gainGOLD = new org.jdom2.Element("gainGOLD");
				startDate.addContent(date.toString());
				run.addContent(runID);
				run.addContent(startDate);
				run.addContent(endDate);
				run.addContent(runLength);
				run.addContent(gainXP);
				run.addContent(gainGOLD);
				org.jdom2.Element startStatus = new org.jdom2.Element(
						"startStatus");
				org.jdom2.Element startXP = new org.jdom2.Element("XP");
				startXP.addContent(XP);
				org.jdom2.Element startGOLD = new org.jdom2.Element("GOLD");
				startGOLD.addContent(GOLD);
				startStatus.addContent(startXP);
				startStatus.addContent(startGOLD);
				run.addContent(startStatus);
				runList.addContent(run);
				currentRunGlobal = run;
				System.out.println("start written");
			}
			if (!startend) {

				org.jdom2.Element currentRun = runList.getChildren().get(
						runList.getChildren().size() - 1);
				currentRun.getChild("endDate").addContent(date);
				org.jdom2.Element startStatus = currentRun
						.getChild("startStatus");
				String startXP_STR = startStatus.getChild("XP").getValue();
				String startGOLD_STR = startStatus.getChild("GOLD").getValue();
				long startXP_NUM = Long.valueOf(startXP_STR);
				long startGOLD_NUM = Long.valueOf(startGOLD_STR);
				long endXP_NUM = Long.valueOf(XP);
				long endGOLD_NUM = Long.valueOf(GOLD);
				currentRun.getChild("gainXP").addContent(
						String.valueOf(endXP_NUM - startXP_NUM));
				currentRun.getChild("gainGOLD").addContent(
						String.valueOf(endGOLD_NUM - startGOLD_NUM));

				org.jdom2.Element endStatus = new org.jdom2.Element("endStatus");
				org.jdom2.Element endXP = new org.jdom2.Element("XP");
				endXP.addContent(XP);
				org.jdom2.Element endGOLD = new org.jdom2.Element("GOLD");
				endGOLD.addContent(GOLD);
				endStatus.addContent(endXP);
				endStatus.addContent(endGOLD);
				currentRun.addContent(endStatus);
				computeAverageXP_GOLD();
				computeAverageLength();
				currentRun.getChild("runLength").addContent(
						String.valueOf(length));

				System.out.println("end written");

			}

		}

		saveChanges();

	}

	public static void saveD3Status() throws ParserConfigurationException,
			TransformerException {

		// DocumentBuilderFactory docFactory = DocumentBuilderFactory
		// .newInstance();
		// DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
		//
		// // root elements
		// Document doc = docBuilder.newDocument();
		// Element rootElement = doc.createElement("d3progress");
		//
		// doc.appendChild(rootElement);
		//
		// // status
		// Element status = doc.createElement("status");
		// status.setAttribute("timeStamp", new Date().toString());
		// status.setAttribute("gold", Main.gui.currentGold);
		// status.setAttribute("xp", Main.gui.currentXP);
		// rootElement.appendChild(status);

		// write the content into xml file
		// TransformerFactory transformerFactory = TransformerFactory
		// .newInstance();
		// Transformer transformer = transformerFactory.newTransformer();
		// DOMSource source = new DOMSource(doc);
		// StreamResult result = new StreamResult(new File(PATH + "file.xml"));
		//
		// // Output to console for testing
		// // StreamResult result = new StreamResult(System.out);
		//
		// transformer.transform(source, result);
		//
		// System.out.println("File saved!");

	}

	public static void saveToDisc(BufferedImage[] images, String path,
			String name) throws IOException {

		// TODO variablen filename einbauen vielleicht datum
		File outputGOLD = new File(path + name + " " + " Gold " + " " + ".png");
		ImageIO.write(images[0], "png", outputGOLD);
		File outputXP = new File(path + name + " " + " XP " + " " + ".png");
		ImageIO.write(images[1], "png", outputXP);
	}

	public static String[] loadLastStatus() throws JDOMException, IOException {
		String[] result = new String[2];

		org.jdom2.Document doc = null;
		File f = new File(PATH);

		SAXBuilder builder = new SAXBuilder();
		doc = builder.build(f);

//		org.jdom2.Element currentBuild = getActivBuild(doc, f);
		List<org.jdom2.Element> statusList = ACTIVE_BUILD
				.getChild("statusList").getChildren();
		org.jdom2.Element lastEle = statusList.get(statusList.size() - 1);

		return result;
	}

	public static String loadResolution() throws JDOMException, IOException {
		String result = "";
		org.jdom2.Document doc = null;
		File f = new File(PATH);

		SAXBuilder builder = new SAXBuilder();
		doc = builder.build(f);
		org.jdom2.Element ele = doc.getRootElement();

		result += ele.getChild("programmStatus").getChild("resolution")
				.getContent(0).getValue();

		return result;
	}

	public static Boolean loadFileSave() throws JDOMException, IOException {
		Boolean result = false;
		org.jdom2.Document doc = null;
		File f = new File(PATH);

		SAXBuilder builder = new SAXBuilder();
		doc = builder.build(f);
		org.jdom2.Element ele = doc.getRootElement();
		Content help = ele.getChild("programmStatus").getChild("fileSave")
				.getContent(0);
		System.out.println(help.getValue());
		if (ele.getChild("programmStatus").getChild("fileSave").getContent(0)
				.getValue().equals("true")) {
			result = true;
		} else {
			result = false;
		}
		return result;
	}

//	public static String getLastActiveBuild() throws JDOMException, IOException {
//		String result = "";
//		result = DOCUMENT.getRootElement().getChild("programmStatus").getChild("lastActivBuild").getValue();
//		return result;
//	}

	public int getParagonLevel() throws JDOMException, IOException {
		int result = 0;
		org.jdom2.Document doc = null;
		File f = new File(PATH);

		SAXBuilder builder = new SAXBuilder();
		doc = builder.build(f);
		org.jdom2.Element ele = doc.getRootElement();
		Content help = ele.getChild("programmStatus").getChild("paragonLevel")
				.getContent(0);
		result = Integer.parseInt(help.getValue());
		return result;
	}

	public static org.jdom2.Element getActivBuild(String lastActivBuild)
			throws JDOMException, IOException {
		Element result = null;
		Iterator<Element> it = BUILD_LIST.iterator();
		while(it.hasNext()){
			Element actual = it.next();
			if(actual.getChild("buildName").getValue().equals(lastActivBuild)){
				result = actual;
			}
		}
		return result;
	}

	public static String getLastGOLD() throws JDOMException, IOException {
		String result = "";

		List<org.jdom2.Element> lastRunList = ACTIVE_BUILD.getChild("runList")
				.getChildren();
		if (lastRunList.isEmpty() == false) {
			org.jdom2.Element lastRun = ACTIVE_BUILD
					.getChild("runList")
					.getChildren()
					.get(ACTIVE_BUILD.getChild("runList").getChildren().size() - 1);
			result = lastRun.getChild("endStatus").getChild("GOLD").getValue();
		}

		return result;
	}

	public static String getLastXP() throws JDOMException, IOException {
		String result = "";
		List<org.jdom2.Element> lastRunList = ACTIVE_BUILD.getChild("runList")
				.getChildren();
		if (lastRunList.isEmpty() == false) {
			org.jdom2.Element lastRun = ACTIVE_BUILD
					.getChild("runList")
					.getChildren()
					.get(ACTIVE_BUILD.getChild("runList").getChildren().size() - 1);
			result = lastRun.getChild("endStatus").getChild("XP").getValue();
		}

		return result;
	}

	public static Long[] computeAverageXP_GOLD() throws JDOMException,
			IOException {
		Long[] result = new Long[2];
		List<org.jdom2.Element> runList = ACTIVE_BUILD.getChild("runList")
				.getChildren();
		Iterator<Element> it = runList.iterator();
		long totalXP = 0;
		long totalGOLD = 0;
		while (it.hasNext()) {
			org.jdom2.Element actual = it.next();
			if (!actual.getChild("gainXP").getValue().equals("")) {
				totalXP += Long.parseLong(actual.getChild("gainXP").getValue());
			}
			if (!actual.getChild("gainGOLD").getValue().equals("")) {
				totalGOLD += Long.parseLong(actual.getChild("gainGOLD")
						.getValue());
			}
		}
		totalXP /= runList.size();
		result[0] = totalXP;
		totalGOLD /= runList.size();
		result[1] = totalGOLD;
		ACTIVE_BUILD.getChild("averageXP").removeContent();
		ACTIVE_BUILD.getChild("averageXP").addContent(String.valueOf(totalXP));
		ACTIVE_BUILD.getChild("averageGOLD").removeContent();
		ACTIVE_BUILD.getChild("averageGOLD").addContent(
				String.valueOf(totalGOLD));
		
		return result;
	}

	public static void computeAverageLength() throws JDOMException,
			IOException {
		List<org.jdom2.Element> runList = ACTIVE_BUILD.getChild("runList")
				.getChildren();
		Iterator<Element> it = runList.iterator();
		long totalLength = 0;
		while (it.hasNext()) {
			org.jdom2.Element actual = it.next();
			if (!actual.getChild("runLength").getValue().equals("")) {
				totalLength += Long.parseLong(actual.getChild("runLength").getValue());
			}
		}
		totalLength /= runList.size();;
		ACTIVE_BUILD.getChild("averageLength").removeContent();
		ACTIVE_BUILD.getChild("averageLength").addContent(String.valueOf(totalLength));
	}

	public static BufferedImage[] loadMatrixImages() throws IOException {
		BufferedImage[] result = new BufferedImage[10];
		for (int i = 0; i < 10; i++) {
			result[i] = ImageIO.read(new File("./matrixPictures/" + i + "-Matrix.png"));
		}
		return result;
	}

	public String[] getAverageXP_GOLD_LENGTH() {
		String[] result = new String[3];
		result[0] = ACTIVE_BUILD.getChild("averageXP").getValue();
		result[1] = ACTIVE_BUILD.getChild("averageGOLD").getValue();
		result[2] = ACTIVE_BUILD.getChild("averageLength").getValue();
		return result;
	}

	public static String getRunLength(String start, String end) {
		String result = "";
		String[] startArray = start.split(":");
		String[] endArray = start.split(":");
		int h = Integer.parseInt(endArray[0]) - Integer.parseInt(startArray[0]);
		int m = Integer.parseInt(endArray[1]) - Integer.parseInt(startArray[1]);
		int s = Integer.parseInt(endArray[2]) - Integer.parseInt(startArray[2]);
		result += h + ":" + m + ":" + s;
		return result;
	}

	public static void saveChanges() throws IOException {
		XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
		FileOutputStream output = new FileOutputStream(PATH);
		outputter.output(DOCUMENT, output);
	}

	public ArrayList<Run> getRunlist() throws ParseException{

		List<Element> runList = ACTIVE_BUILD.getChild("runList").getChildren();
		ArrayList<Run> result = new ArrayList<Run>();
		Iterator<org.jdom2.Element> it = runList.iterator();
		int index = 0;
		while (it.hasNext()) {
			org.jdom2.Element actual = it.next();
			String format = "EEE MMMM dd hh:mm:ss z yyyy"; // EEE MMMM FF hh:mm:ss z yyyy
			Date startDate = new SimpleDateFormat(format,Locale.ENGLISH).parse(actual.getChild("startDate").getValue());
			Date endDate = new SimpleDateFormat(format,Locale.ENGLISH).parse(actual.getChild("endDate").getValue());
			String startXP = actual.getChild("startStatus").getChild("XP").getValue();
			String endXP = actual.getChild("endStatus").getChild("XP").getValue();
			String startGOLD = actual.getChild("startStatus").getChild("GOLD").getValue();
			String endGOLD = actual.getChild("endStatus").getChild("GOLD").getValue();
			System.out.println(actual.getChild("startDate").getValue() + " " + actual.getChild("endDate").getValue() + " " + " conversts too: " + " " + startDate.toString() + " " + endDate.toString() );
			Run help = new Run(startDate,endDate,startXP,startGOLD,endXP,endGOLD);
			result.add(help);
			index++;
		}
		
		
		return result;
	}
	
	public static List<Element> getBuildList(){
		List<Element> result = null;
		result = DOCUMENT.getRootElement().getChild("builds").getChildren();
		return result;
	}
	
	public static void initDOC(String fileName) throws IOException {
		// INIT DOC
		org.jdom2.Document dokument = new org.jdom2.Document(new Element(
				"d3tracker"));

		// tree programmstatus
		Element programStatus = new Element("programmStatus");
		Element lastActivBuild = new Element("lastActivBuild");
		Element resolution = new Element("resolution");
		resolution.addContent("1440x900");
		Element paragonLevel = new Element("paragonLevel");
		paragonLevel.addContent("30"); // TODO PARAGONLEVEL eintragen
		Element fileSave = new Element("fileSave");
		fileSave.addContent("true"); // TODO TRUE / FLASE in die Gui
		// einarbeiten
		lastActivBuild.addContent("1");

		programStatus.addContent(lastActivBuild);
		programStatus.addContent(fileSave);
		programStatus.addContent(paragonLevel);
		programStatus.addContent(resolution);

		// tree current build
		Element builds = new Element("builds");
		Element buildID = new Element("buildID");
		Element build = new Element("build");
		Element averageXP = new Element("averageXP");
		Element averageGOLD = new Element("averageGOLD");
		Element averageLength = new Element("averageLength");
		Element runList = new Element("runList");
		Element run = new Element("run");
		Element stats = new Element("stats");
		Element skills = new Element("skills");

		// stats
		Element str = new Element("strength");
		Element dex = new Element("dexterity");
		Element intelligence = new Element("intelligence");
		Element vit = new Element("vitality");
		Element armor = new Element("armor");
		Element dmg = new Element("damage");
		str.addContent("352");
		dex.addContent("209");
		intelligence.addContent("2120");
		vit.addContent("749");
		armor.addContent("3793");
		dmg.addContent("48377");
		// add everything of stats to stats
		stats.addContent(str);
		stats.addContent(dex);
		stats.addContent(intelligence);
		stats.addContent(vit);
		stats.addContent(armor);
		stats.addContent(dmg);

		// add id to build
		buildID.addContent("1");
		build.addContent(buildID);
		// average stuff
		build.addContent(averageXP);
		build.addContent(averageGOLD);
		build.addContent(averageLength);
		// add stats to build
		build.addContent(stats);

		// skills TO DO
		build.addContent(skills);

		// status
		Element runID = new Element("id");
		runID.addContent("1"); // TODO vortlaufende ID adden
		Element runDate = new Element("date");
		Date date = new Date();
		runDate.addContent(date.toString());
		run.addContent(runID);
		run.addContent(runDate);

		Element startStatus = new Element("startStatus");
		Element startXP = new Element("XP");
		startXP.addContent("1111");
		Element startGOLD = new Element("GOLD");
		startGOLD.addContent("9999");
		startStatus.addContent(startXP);
		startStatus.addContent(startGOLD);

		Element endStatus = new Element("endStatus");
		Element endXP = new Element("XP");
		endXP.addContent("2222");
		Element endGOLD = new Element("GOLD");
		endGOLD.addContent("18000");
		endStatus.addContent(endXP);
		endStatus.addContent(endGOLD);

		run.addContent(startStatus);
		run.addContent(endStatus);

		runList.addContent(run);

		// add status to statuslist
		build.addContent(runList);
		builds.addContent(build);

		// add everything to root
		dokument.getRootElement().addContent(programStatus);
		dokument.getRootElement().addContent(builds);

		XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
		FileOutputStream output = new FileOutputStream(fileName);
		outputter.output(dokument, output);
		System.out.println("file written");
	}
}
